package cn.mjnxin.iot.base.log;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import cn.mjnxin.iot.base.concurrent.ThreadFactoryImpl;
import cn.mjnxin.iot.base.process.IWorker;
import cn.mjnxin.iot.base.util.CommonUtil;
import cn.mjnxin.iot.base.util.MixUtil;
import io.netty.buffer.ByteBuf;

/**
 * 上行报文中转
 * @Description: 终端报文实际发送前置
 * @author CLG 2023年10月10日
 * @version V1.0.0
 */
public class LogThread implements IWorker{
    /**
     * 是否不打印日志
     */
    public static  boolean                          nolog              = false;
    private static BlockingQueue<LogData>           logQueue           = new LinkedBlockingQueue<LogData>();
    private static boolean                          isWorking          = false;
    private final  int                              poolSize;
    private final                                   ExecutorService exService;
    public LogThread(int poolSize) {
        super();
        this.poolSize = poolSize;
        exService = Executors.newFixedThreadPool(poolSize, new ThreadFactoryImpl("msgLogWorker_", false));
    }

    /**
     * 非强制模式是否可以记录日志
     * @return
     */
    public static boolean isLogable() {
        return isWorking;
    }
    
    public static void log(String logMsg) {
    	innerLog(null, logMsg, false);
    }

    public static void log(String logMsg, ByteBuf byteBuf) {
        innerLog(byteBuf, logMsg, true);
    }

    public static void logForce(String logMsg) {
    	innerLogForce(null, logMsg, false);
    }
    
    public static void logForce(ByteBuf byteBuf, String logMsg) {
        innerLogForce(byteBuf, logMsg, true);
    }

    public static void log(String logMsg, byte[] buf) {
        if (isWorking) {
            try {
                logQueue.put(new LogData(buf, logMsg, false));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void logForce(String logMsg, byte[] buf) {
        if (isWorking) {
            try {
                logQueue.put(new LogData(buf, logMsg, false));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        else {
        	logging(logMsg, buf);
        }
    }

    public static void error(String logMsg, Throwable t) {
        try {
            System.err.println(logMsg);
            t.printStackTrace();
        }finally {
        }
    }

    private static void innerLog(ByteBuf byteBuf, String logMsg, boolean isRelease) {
        if (isWorking) {
            try {
            	if (byteBuf != null) {
                    byteBuf.readerIndex(0);
                    byte[] dst = new byte[byteBuf.readableBytes()];
                    byteBuf.readBytes(dst);
                    byteBuf.readerIndex(0);
                    logQueue.put(new LogData(dst, logMsg, isRelease));
            	}
            	else {
                    logQueue.put(new LogData(null, logMsg, false));
            	}
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static void innerLogForce(ByteBuf byteBuf, String logMsg, boolean isRelease) {
        if (isWorking) {
            try {
            	if (byteBuf != null) {
	                byteBuf.readerIndex(0);
	                byte[] dst = new byte[byteBuf.readableBytes()];
	                byteBuf.readBytes(dst);
	                byteBuf.readerIndex(0);
	                logQueue.put(new LogData(dst, logMsg, false));
            	}
            	else {
	                logQueue.put(new LogData(null, logMsg, false));
            	}
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        else {
            logging(byteBuf, logMsg, isRelease);
        }
    }

    public void run() {
        isWorking = true;
        final int[] working = new int[] {poolSize};
        for (int i=0 ; i < poolSize ; i++ ){
            exService.execute(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        LogData logData = null;
                        try {
                            logData = logQueue.take();//获取从Gate4Terminal发送过来的上行报文对象
                        } catch (Exception e) {
                            e.printStackTrace();
                            working[0]--;
                            if (working[0] == 0) {
                                isWorking = false;
                            }
                            break;
                        }
                        if(logData == null){
                            continue;
                        }
                        try {
                            logging(logData.getLogMsg(), logData.getBuf());
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
    }

    @Override
    public void start() throws Exception {
        new Thread(this).start();
    }

    private static void logging(ByteBuf byteBuf, String logMsg, boolean isRelease) {
        try {
            if(byteBuf != null) {
                byteBuf.readerIndex(0);
                byte[] dst = new byte[byteBuf.readableBytes()];
                byteBuf.readBytes(dst);
                byteBuf.readerIndex(0);
                System.out.println(logMsg + MixUtil.bytes2hex(dst));
            }
            else {
            	System.out.println(logMsg);
            }
        }finally {
            if (isRelease && byteBuf != null) {
                CommonUtil.releaseByteBuf(byteBuf);
            }
        }
    }

    private static void logging(String logMsg, byte[] buf) {
        if(buf != null) {
        	System.out.println(logMsg + MixUtil.bytes2hex(buf));
        }
        else {
        	System.out.println(logMsg);
        }
    }
}
